package cfca.seal.factory;

import cfca.com.itextpdf.text.pdf.security.BouncyCastleDigest;
import cfca.com.itextpdf.text.pdf.security.ExternalDigest;
import cfca.com.itextpdf.text.pdf.security.ExternalSignature;
import cfca.sadk.algorithm.common.Mechanism;
import cfca.sadk.algorithm.sm2.SM2PrivateKey;
import cfca.sadk.lib.crypto.JCrypto;
import cfca.sadk.lib.crypto.Session;
import cfca.sadk.util.Base64;
import cfca.sadk.util.KeyUtil;
import cfca.sadk.x509.certificate.X509Cert;
import cfca.seal.bean.Seal;
import cfca.seal.bean.SealCert;
import cfca.seal.sadk.PrePdfSeal;
import cfca.seal.sadk.security.external.DoneExternalSessionSignature;
import cfca.seal.sadk.security.external.DoneExternalSessionSignatureExtra;
import cfca.seal.sadk.security.external.ExternalSessionSignatureExtra;
import cfca.seal.sadk.security.external.PreExternalSessionSignatureParameter;
import cfca.seal.util.EncryptUtil;
import cfca.seal.util.JHARDUtil;
import cfca.seal.util.SealCertUtil;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PrivateKey;

public class PrePdfSealFactory
{
  public static PrePdfSeal generatePrePdfSeal(Seal seal)
    throws Exception
  {
    PrePdfSeal pdfSeal = new PrePdfSeal(seal.getSealData(), EncryptUtil.decrypto(seal.getSealPfxPwd()), 0.68F);
    return pdfSeal;
  }

  public static PrePdfSeal generatePrePdfSealSm2(Seal seal) throws Exception
  {
    JCrypto.getInstance().initialize("JSOFT_LIB", null);
    Session session = JCrypto.getInstance().openSession("JSOFT_LIB");
    PrePdfSeal pdfSeal = new PrePdfSeal(seal.getSealData(), EncryptUtil.decrypto(seal.getSealPfxPwd()), 0.68F, "SM3", session);
    return pdfSeal;
  }

  public static PrePdfSeal generatePrePdfSeal(Seal seal, SealCert cert) throws Exception {
    PrePdfSeal pdfSeal = null;

    JCrypto.getInstance().initialize(cert.getDevice(), null);
    Session session = JCrypto.getInstance().openSession(cert.getDevice());
    PrivateKey privateKey = null;
    if (cert.getDevice().equals("JHARD_LIB")) {
      privateKey = JHARDUtil.getPrivateKeyFromHard(cert.getKeyId(), session);
    } else if (cert.getDevice().equals("JSOFT_LIB")) {
      cert.decryptCiphertext(cert);
      if ("SHA1RSA".equals(cert.getCertAlg()))
        privateKey = (PrivateKey)SealCertUtil.getRSAPrivateKey(Base64.decode(cert.getPrivateKeyData()));
      else {
        privateKey = SM2PrivateKey.getInstance(Base64.decode(cert.getPrivateKeyData()));
      }
    }
    X509Cert x509Cert = new X509Cert(cert.getPublickCertData());
    ExternalDigest externalDigest = new BouncyCastleDigest();

    final DoneExternalSessionSignature externalSignature = new DoneExternalSessionSignature(privateKey, "SHA-1", session);
    PreExternalSessionSignatureParameter externalSessionSignatureParameter = new PreExternalSessionSignatureParameter(x509Cert)
    {
      public byte[] getSignatureBytes(byte[] authenticateAttributeBytes) {
        try {
          return externalSignature.sign(authenticateAttributeBytes);
        } catch (GeneralSecurityException e) {
          throw new RuntimeException(e.getMessage());
        }
      }
    };
    ExternalSessionSignatureExtra externalSessionSignatureExtra = new DoneExternalSessionSignatureExtra(externalDigest, externalSignature, externalSessionSignatureParameter);
    pdfSeal = new PrePdfSeal(null, null, externalSessionSignatureExtra, externalSessionSignatureParameter, seal.getSealImageData(), 0.68F);
    return pdfSeal;
  }

  public static PrePdfSeal generatePrePdfSeal(Seal seal, byte[] x509Cert, final byte[] p1Signature) throws Exception
  {
    PrePdfSeal pdfSeal = null;

    JCrypto.getInstance().initialize("JSOFT_LIB", null);
    Session session = JCrypto.getInstance().openSession("JSOFT_LIB");
    X509Cert cert = new X509Cert(x509Cert);
    PrivateKey privateKey = KeyUtil.generateKeyPair(new Mechanism("RSA"), 1024, session).getPrivate();
    ExternalDigest externalDigest = new BouncyCastleDigest();
    ExternalSignature externalSignature = new DoneExternalSessionSignature(privateKey, "SHA-1", session);
    PreExternalSessionSignatureParameter externalSessionSignatureParameter = new PreExternalSessionSignatureParameter(cert)
    {
      public byte[] getSignatureBytes(byte[] authenticateAttributeBytes) {
        return p1Signature;
      }
    };
    ExternalSessionSignatureExtra externalSessionSignatureExtra = new DoneExternalSessionSignatureExtra(externalDigest, externalSignature, externalSessionSignatureParameter);
    pdfSeal = new PrePdfSeal(null, null, externalSessionSignatureExtra, externalSessionSignatureParameter, seal.getSealImageData(), 0.68F);
    return pdfSeal;
  }
}